package htmlsoup

import (
	"bytes"
)

type htmlTagMapSetting struct {
	validParents, inValidParents, validChildren []string
	forcedClosed                                []string
	isBlock, canBeBlock, useEndTag              bool
	isValid                                     bool
	isOutput                                    bool
	isClosed                                    bool
	isHeadDecendent, isBodyDecendent            bool
	pauseBefore                                 bool
	writeHandler                                func(*SoupNode, *bytes.Buffer)
	voiceHandler                                func(*SoupNode, *bytes.Buffer)
	attributesURLHandler                        func(*SoupNode)
}

var htmlTagDefaultSettings map[string]htmlTagMapSetting

func initTagMapValue() htmlTagMapSetting {
	var tmv htmlTagMapSetting
	tmv.validParents = []string{}
	tmv.inValidParents = []string{}
	tmv.validChildren = []string{}
	tmv.forcedClosed = []string{}
	tmv.isBlock = false
	tmv.canBeBlock = false
	tmv.useEndTag = true
	tmv.isValid = true
	tmv.isOutput = true
	tmv.pauseBefore = false
	tmv.isHeadDecendent = false
	tmv.isBodyDecendent = false
	tmv.writeHandler = writeToBufferTag
	tmv.voiceHandler = writeToBufferNoVoice
	tmv.attributesURLHandler = checkNoAttribute
	return tmv
}

func htmlTagMapValueInLine() htmlTagMapSetting {
	tmv := initTagMapValue()
	return tmv
}

func htmlTagMapValueInLineBlock() htmlTagMapSetting {
	tmv := initTagMapValue()
	tmv.canBeBlock = true
	return tmv
}

func htmlTagMapValueBlock() htmlTagMapSetting {
	tmv := initTagMapValue()
	tmv.isBlock = true
	return tmv
}

func init() {
	// invalids
	var name string
	var tmv htmlTagMapSetting
	htmlTagDefaultSettings = make(map[string]htmlTagMapSetting)
	htmlInvalidTags := []string{
		"applet",
		"basefont", "bdi",
		"canvas", "command", "col", "colgroup",
		"dialog", "del",
		"frameset", "frame",
		"isindex",
		"menu", "menuitem",
		"noframes",
		"output",
		"progress",
		"row", "rowgroup", "ruby", "rt", "rp",
		"s", "strike", "style",
		"table", "tbody", "td", "tfoot", "th", "thead", "tr",
		"wbr",
	}
	for _, name = range htmlInvalidTags {
		tmv = htmlTagMapValueInLineBlock()
		tmv.isOutput = false
		htmlTagDefaultSettings[name] = tmv
	}
	htmlSimpleInlineBlockTags := []string{
		"article", "aside",
		"b", "big",
		"center", "cite",
		"details", "dfn",
		"em",
		"font", "footer",
		"i", "ins", "noscript",
		"kbd",
		"mark", "main",
		"nav",
		"samp", "span", "strong", "sub", "sup", "small", "summary",
		"tt",
		"u",
		"var",
	}
	for _, name = range htmlSimpleInlineBlockTags {
		tmv = htmlTagMapValueInLineBlock()
		tmv.isBodyDecendent = true
		htmlTagDefaultSettings[name] = tmv
	}
	// a
	tmv = htmlTagMapValueInLineBlock()
	tmv.isBodyDecendent = true
	tmv.attributesURLHandler = checkHrefAttribute
	htmlTagDefaultSettings["a"] = tmv
	// abbr (title = "")
	tmv = htmlTagMapValueInLineBlock()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["abbr"] = tmv
	// acronym
	tmv = htmlTagMapValueInLineBlock()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["acronym"] = tmv
	// address
	tmv = htmlTagMapValueInLineBlock()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["address"] = tmv
	// area
	// only valid if has "title" or "alt" attribute
	//  which is the spoken text.
	tmv = htmlTagMapValueInLineBlock()
	tmv.validParents = []string{"map"}
	htmlTagDefaultSettings["area"] = tmv
	// audio
	tmv = htmlTagMapValueInLine()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["audio"] = tmv
	// base
	tmv = htmlTagMapValueInLine()
	tmv.isHeadDecendent = true
	tmv.attributesURLHandler = checkBaseTagHrefAttribute
	htmlTagDefaultSettings["base"] = tmv
	// bdo
	tmv = htmlTagMapValueInLineBlock()
	htmlTagDefaultSettings["bdo"] = tmv
	// blockquote
	tmv = htmlTagMapValueBlock()
	tmv.pauseBefore = true
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["blockquote"] = tmv
	// body
	tmv = htmlTagMapValueBlock()
	tmv.validParents = []string{"html"}
	htmlTagDefaultSettings["body"] = tmv
	// br
	tmv = htmlTagMapValueInLineBlock()
	tmv.useEndTag = false
	tmv.isClosed = true
	tmv.pauseBefore = true
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["br"] = tmv
	// button
	tmv = htmlTagMapValueInLineBlock()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["button"] = tmv
	// canvas
	tmv = htmlTagMapValueInLineBlock()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["canvas"] = tmv
	// code
	tmv = htmlTagMapValueInLine()
	tmv.pauseBefore = true
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["code"] = tmv
	// datalist (for input)
	tmv = htmlTagMapValueInLine()
	tmv.validChildren = []string{"li"}
	tmv.validParents = []string{"input"}
	htmlTagDefaultSettings["datalist"] = tmv
	// dir
	tmv = htmlTagMapValueBlock()
	tmv.validChildren = []string{"li"}
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["dir"] = tmv
	// div
	tmv = htmlTagMapValueBlock()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["div"] = tmv
	// dl
	tmv = htmlTagMapValueInLine()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["dl"] = tmv
	// dd & dt
	tmv = htmlTagMapValueInLine()
	tmv.validParents = []string{"dl"}
	htmlTagDefaultSettings["dd"] = tmv
	tmv.pauseBefore = true
	htmlTagDefaultSettings["dt"] = tmv
	// embed
	tmv = htmlTagMapValueInLineBlock()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["embed"] = tmv
	// fieldset
	tmv = htmlTagMapValueInLineBlock()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["fieldset"] = tmv
	// figcaption
	tmv = htmlTagMapValueInLine()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["figcaption"] = tmv
	// figure
	tmv = htmlTagMapValueInLine()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["figure"] = tmv
	// form
	tmv = htmlTagMapValueInLineBlock()
	tmv.isBodyDecendent = true
	tmv.attributesURLHandler = checkFormActionAttribute
	htmlTagDefaultSettings["form"] = tmv
	// h1-6
	tmv = htmlTagMapValueBlock()
	tmv.pauseBefore = true
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["h1"] = tmv
	htmlTagDefaultSettings["h2"] = tmv
	htmlTagDefaultSettings["h3"] = tmv
	htmlTagDefaultSettings["h4"] = tmv
	htmlTagDefaultSettings["h5"] = tmv
	htmlTagDefaultSettings["h6"] = tmv
	htmlTagDefaultSettings["header"] = tmv
	// head
	tmv = htmlTagMapValueBlock()
	tmv.validParents = []string{"html"}
	htmlTagDefaultSettings["head"] = tmv
	// hgroup
	tmv = htmlTagMapValueInLine()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["hgroup"] = tmv
	// horizonal rule
	tmv = htmlTagMapValueBlock()
	tmv.pauseBefore = true
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["hr"] = tmv
	// html
	tmv = htmlTagMapValueBlock()
	tmv.validParents = []string{"document"}
	htmlTagDefaultSettings["html"] = tmv
	// iframe
	tmv = htmlTagMapValueBlock()
	tmv.isBodyDecendent = true
	//tmv.isOutput = false
	htmlTagDefaultSettings["iframe"] = tmv
	// img
	tmv = htmlTagMapValueInLine()
	tmv.pauseBefore = true
	tmv.voiceHandler = writeToBufferImageVoice
	tmv.isBodyDecendent = true
	tmv.attributesURLHandler = checkSrcAttribute
	tmv.useEndTag = false
	htmlTagDefaultSettings["img"] = tmv
	// input
	tmv = htmlTagMapValueInLine()
	tmv.inValidParents = []string{"button"}
	tmv.isBodyDecendent = true
	tmv.useEndTag = false
	htmlTagDefaultSettings["input"] = tmv
	// keygen
	tmv = htmlTagMapValueInLine()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["keygen"] = tmv
	// label
	tmv = htmlTagMapValueInLine()
	tmv.inValidParents = []string{"button"}
	tmv.isBodyDecendent = true
	tmv.voiceHandler = writeToBufferNoVoice // writeToBufferLabelVoice
	htmlTagDefaultSettings["label"] = tmv
	// legend
	tmv = htmlTagMapValueInLine()
	tmv.validParents = []string{"fieldset"}
	htmlTagDefaultSettings["legend"] = tmv
	// li
	tmv = htmlTagMapValueInLine()
	tmv.validParents = []string{"ul", "ol", "menu", "dir", "datalist"}
	tmv.pauseBefore = true
	tmv.forcedClosed = []string{"li"}
	htmlTagDefaultSettings["li"] = tmv
	// link
	tmv = htmlTagMapValueInLine()
	tmv.isHeadDecendent = true
	tmv.useEndTag = false
	tmv.isClosed = true
	tmv.attributesURLHandler = checkLinkTagHrefAttribute
	htmlTagDefaultSettings["link"] = tmv
	// meta
	tmv = htmlTagMapValueInLine()
	tmv.isHeadDecendent = true
	tmv.useEndTag = false
	tmv.isClosed = true
	htmlTagDefaultSettings["meta"] = tmv
	// noscript
	tmv = htmlTagMapValueInLineBlock()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["noscript"] = tmv
	// object
	tmv = htmlTagMapValueInLine()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["object"] = tmv
	// option
	tmv = htmlTagMapValueInLine()
	tmv.validParents = []string{"select", "optgroup"}
	tmv.forcedClosed = []string{"option"}
	htmlTagDefaultSettings["option"] = tmv
	// optgroup
	tmv = htmlTagMapValueInLine()
	tmv.validParents = []string{"select"}
	tmv.forcedClosed = []string{"optgroup", "option"}
	htmlTagDefaultSettings["optgroup"] = tmv
	// param
	tmv = htmlTagMapValueInLine()
	tmv.validParents = []string{"object"}
	htmlTagDefaultSettings["param"] = tmv
	// p
	tmv = htmlTagMapValueBlock()
	tmv.pauseBefore = true
	tmv.forcedClosed = []string{"p"}
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["p"] = tmv
	// pre
	tmv = htmlTagMapValueBlock()
	tmv.pauseBefore = true
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["pre"] = tmv
	// script
	tmv = htmlTagMapValueInLine()
	tmv.isOutput = false
	htmlTagDefaultSettings["script"] = tmv
	// source & track
	tmv = htmlTagMapValueInLine()
	tmv.validParents = []string{"audio", "video"}
	htmlTagDefaultSettings["source"] = tmv
	htmlTagDefaultSettings["track"] = tmv
	// select
	tmv = htmlTagMapValueInLine()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["select"] = tmv
	// textarea
	tmv = htmlTagMapValueInLineBlock()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["textarea"] = tmv
	// time
	tmv = htmlTagMapValueInLine()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["time"] = tmv
	// title
	tmv = htmlTagMapValueInLine()
	tmv.validParents = []string{"head"}
	tmv.isHeadDecendent = true
	htmlTagDefaultSettings["title"] = tmv
	// ul
	tmv = htmlTagMapValueBlock()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["ul"] = tmv
	// video
	tmv = htmlTagMapValueInLine()
	tmv.isBodyDecendent = true
	htmlTagDefaultSettings["video"] = tmv
}
